﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TribesPSO
{
    internal static class Extensions
    {
        /// <summary>
        /// Returns the elements in an IList in a random order
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="toRandomize"></param>
        /// <returns></returns>
        public static IEnumerable<T> InRandomOrder<T>(this IList<T> toRandomize)
        {
            Random rng = new Random();
            return InRandomOrder(toRandomize, rng);
        }

        /// <summary>
        /// Returns the elements in an IList in a random order using the specified rng
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="toRandomize"></param>
        /// <param name="rng">The random number generator used to determine the order</param>
        /// <returns></returns>
        public static IEnumerable<T> InRandomOrder<T>(this IList<T> toRandomize, IRandom rng)
        {
            List<KeyValuePair<double, int>> RandomOrder = new List<KeyValuePair<double, int>>(toRandomize.Count());
            for (int n = 0; n < toRandomize.Count(); n++)
            {
                RandomOrder.Add(new KeyValuePair<double, int>(rng.NextDouble(), n));
            }
            foreach (KeyValuePair<double, int> i in RandomOrder.OrderBy(o => o.Key))
            {
                yield return toRandomize.ElementAt(i.Value);
            }
        }

        /// <summary>
        /// Checks if a IEnumerable contains no items
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns>True if the IEnumerable contains no items.  Otherwise false</returns>
        public static bool IsEmpty<T>(this IEnumerable<T> source)
        {
            return !source.Any();
        }

        /// <summary>
        /// Splits an IEnumerable into groups
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ToSplit"></param>
        /// <param name="targetGroupSize">The target number of elements in each group</param>
        /// <returns>N groups of P elements.  Note that if the total number of elements in the group is not
        /// divisble by P, then the last group will contain fewer than P elements</returns>
        public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> ToSplit, int targetGroupSize)
        {
            IEnumerator<T> enumerator = ToSplit.GetEnumerator();
            List<T> splitList = new List<T>();

            while (enumerator.MoveNext())
            {
                splitList.Add(enumerator.Current);
                if (splitList.Count() >= targetGroupSize)
                {
                    yield return splitList;
                    splitList = new List<T>();
                }
            }
            if (splitList.Any())//return the remaining elements if there are any
                yield return splitList;
        }
    }
}
